<template>
  <AddOrEditDialog
    ref="addOrEditDialogRef"
    dialogWidth="750px"
    :form="form"
    :formInline="true"
    :formRules="formRules"
    title="菜单"
    :formHeader="formHeader"
    :url="$urls.API_URL_BACKSTAGE_PERMISSION_MANAGE"
    :action="action"
    @afterSubmitSuccess="afterSubmitSuccess"
  >
    <template #parentId="scope">
      <SysPermissionTreeSelect
        v-model="form['parentId']"
        :data="table.data"
        :disabled="scope.item.disabled"
        clearable/>
    </template>
    <template #type>
      <el-radio-group v-model="form['type']" @change="showFormItemByType">
        <el-radio :label="1">菜单</el-radio>
        <el-radio :label="2">按钮</el-radio>
      </el-radio-group>
    </template>
    <template #linkType="scope">
      <el-radio-group v-model="form['linkType']" :disabled="scope.item.disabled" @change="showFormItemByLinkType">
        <el-radio :label="1">组件</el-radio>
        <el-radio :label="2">内链</el-radio>
        <el-radio :label="3">外链</el-radio>
      </el-radio-group>
    </template>
    <template #sort>
      <el-input-number
        v-model="form['sort']"
        :min="-1000"
        :max="1000"
        :precision="0"
        placeholder="升序排列"
        style="width: 217px;"
        controls-position="right"
        clearable
      />
    </template>
  </AddOrEditDialog>
</template>

<script lang="ts" setup>
import AddOrEditDialog from '@/components/base/table/form/AddOrEditDialog.vue';
import SysPermissionTreeSelect from '@/components/uem/SysPermissionTreeSelect.vue';

import {
  computed,
  defineExpose, defineProps, getCurrentInstance, onMounted, reactive, ref, withDefaults,
} from 'vue';
import { TableColumn, FormHeader, TableData } from '@/types/interface/base_interface';
import { Option, yesOrNoDict } from '@/api/dict';
import { Department, Permission } from '@/types/interface/auth_interface';
import * as Icons from '@element-plus/icons-vue';

const { proxy } = getCurrentInstance();
// 接收父容器参数
interface Props {
  table: TableData, // 表格对象，包含表格数据和分页信息。表格数据实际业务并不需要，偷懒写法
  action?: string, // 表单的处理类型，post表示提交，put表示编辑
}
const props = withDefaults(defineProps<Props>(), {
  action: 'post',
});
// 表单元素
const formHeader = ref<FormHeader[]>([
  {
    label: '上级菜单',
    prop: 'parentId',
    type: 'custom',
  },
  {
    label: '菜单类型',
    prop: 'type',
    type: 'custom',
  },
  {
    label: '菜单名称',
    prop: 'name',
  },
  {
    label: '打开方式',
    prop: 'linkType',
    type: 'custom',
  },
  {
    label: '下划线',
    prop: 'divider',
    type: 'divider',
  },
  {
    label: '菜单图标',
    prop: 'iconCls',
    type: 'iconSelect',
  },
  {
    label: '权限标识',
    prop: 'permission',
  },
  {
    label: '组件名称',
    prop: 'component',
    placeholder: '唯一字段，对应router的name属性',
    rules: [
      {
        required: true,
        message: '不能为空',
        trigger: 'blur',
      },
      {
        min: 1,
        max: 30,
        message: '必须在1-30个字符之间',
        trigger: 'blur',
      },
    ],
  },
  {
    label: '组件地址',
    prop: 'path',
    placeholder: '路由component属性：/page/permissionmanage/Index.vue',
    rules: [
      // 考虑到如果菜单有子菜单并不会打开，因此路径这里不作为必填
      // {
      //   required: true,
      //   message: '不能为空',
      //   trigger: 'blur',
      // },
      {
        max: 200,
        message: '不能超过200个字符',
        trigger: 'blur',
      },
    ],
  },
  {
    label: '路由路径',
    prop: 'route',
    placeholder: '对应router的path',
    rules: [
      {
        required: true,
        message: '不能为空',
        trigger: 'blur',
      },
      {
        max: 200,
        message: '不能超过200个字符',
        trigger: 'blur',
      },
    ],
  },
  {
    label: '转发地址',
    prop: 'redirect',
    placeholder: '对应router的redirect',
    rules: [
      {
        max: 200,
        message: '不能超过200个字符',
        trigger: 'blur',
      },
    ],
  },
  {
    label: '链接地址',
    prop: 'url',
    rules: [
      {
        required: true,
        message: '不能为空',
        trigger: 'blur',
      },
      {
        max: 200,
        message: '不能超过200个字符',
        trigger: 'blur',
      },
    ],
  },
  {
    label: '排序',
    prop: 'sort',
    type: 'custom',
    placeholder: '升序排列',
    rules: [
      {
        required: true,
        message: '不能为空',
        trigger: 'blur',
      },
    ],
  },
  {
    label: '是否可见',
    prop: 'display',
    type: 'switch',
  },
  {
    label: '是否可用',
    prop: 'enabled',
    type: 'switch',
  },
  {
    label: '要求登录',
    prop: 'requireAuth',
    type: 'switch',
  },
]);
// 表单对象
const form = ref<Permission>();
let formInit:Permission; // 记录表单第一次传入的值,用于表单重置恢复初始值使用
const addOrEditDialogRef = ref(); // 表单ref对象
// 表单验证规则，用于全局表单验证
const formRules = reactive({
  name: [
    {
      required: true,
      message: '不能为空',
      trigger: 'blur',
    },
    {
      min: 1,
      max: 30,
      message: '必须在1-30个字符之间',
      trigger: 'blur',
    },
  ],
  sort: [
    {
      required: true,
      message: '不能为空',
      trigger: 'blur',
    },
  ],
});
/**
 * 当点击菜单类型和链接类型时，表单的切换动作
 * 1.当菜单类型为按钮时
 * 说明：不涉及前端vue组件和链接的相关属性
 * 2.当菜单类型为菜单时
 * (1)组件
 * 说明：常规模式，即该菜单为组件类型，对应route的一个组件
 * (2)内链
 * 说明：该菜单只负责内部路由跳转，例如某组件已经存在，通过内链可以跳转到其他组件，类似于router的index文件中的redirect属性
 * (3)外链
 * 说明：跳转到外部链接
 */
// 当链接类型发生变化时，下列组件发生变化。下列组件只用于菜单的组件类型
const componentArray = ['component', 'route', 'path', 'redirect', 'url'];
// 当打开方式发生变化时
const showFormItemByLinkType = (value?:number) => {
  if (form.value) {
    if (typeof value !== 'undefined') { // 只有通过链接类别触发的函数，才进行值的重新修改
      form.value.linkType = value; // 因为该函数也用于提供给其他方法调用，因此这里加一个赋值。
    }
    if (form.value.type === 1) { // 如果是菜单可用
      if (form.value.linkType === 1) { // 如果是链接类型是组件
        formHeader.value.forEach((itemNeedEdit: FormHeader) => { // 遍历表单元素数组,将所有元素设置为可用
          if (itemNeedEdit.prop === 'url') { // 让链接表单消失
            itemNeedEdit.disabled = true;
            itemNeedEdit.show = false;
          } else {
            itemNeedEdit.disabled = false;
            itemNeedEdit.show = true;
          }
        });
      } else if (form.value.linkType === 2 || form.value.linkType === 3) { // 如果是内部链接或外部链接，则不需要权限标识和组件地址
        formHeader.value!.forEach((itemNeedEdit: FormHeader) => { // 遍历表单元素数组,将所有元素设置为可用
          if (itemNeedEdit.prop === 'path' || itemNeedEdit.prop === 'permission' || itemNeedEdit.prop === 'redirect') { // 让表单组件地址不可用
            itemNeedEdit.show = false;
            itemNeedEdit.disabled = true;
          }
          if (itemNeedEdit.prop === 'url') { // 让表单链接元素可用
            itemNeedEdit.show = true;
            itemNeedEdit.disabled = false;
          }
        });
      }
    }
  }
};
// 根据菜单类型显示表单元素
const showFormItemByType = (value?:number) => {
  if (typeof value !== 'undefined') {
    form.value!.type = value; // 因为该函数也用于提供给其他方法调用，因此这里加一个赋值。
  }
  if (form.value!.type === 1) { // 如果是菜单,则所有属性都可用。当切换为菜单时，菜单类型默认为组件
    formHeader.value!.forEach((itemNeedEdit:FormHeader) => { // 遍历表单元素数组
      if (itemNeedEdit.prop === 'linkType') {
        itemNeedEdit.disabled = false; // 链接类别表单元素变为可以操作
        showFormItemByLinkType(); // 让其余组件做相应的变化
      }
    });
  } else { // 如果是按钮
    form.value!.linkType = 1; // 打开方式恢复为组件类型
    formHeader.value!.forEach((itemNeedEdit:FormHeader) => { // 遍历表单元素数组
      if (itemNeedEdit.prop === 'linkType') { // 让菜单类型变为不可以操作
        itemNeedEdit.disabled = true;
      } else if (componentArray.includes(itemNeedEdit.prop as string)) { // 相关组件不可使用
        itemNeedEdit.disabled = true;
        itemNeedEdit.show = false;
      }
    });
  }
};
// 打开对话框供父组件调用，传入表单对象
const openDialog = (permission: Permission) => {
  formInit = { ...permission }; // 获取初始值，这里要做深拷贝，避免与form对象引用的地址一致，导致无法恢复初始值
  form.value = { ...permission };
  showFormItemByType(); // 根据菜单类型显示表单元素
  addOrEditDialogRef.value!.openDialog();
};
const afterSubmitSuccess = (resData:any) => { // 钩子函数，提交表单后的操作
  form.value = { ...formInit }; // 恢复为表单初始值，必须这样恢复，因为父子组件的传递问题，不能用element自带的form重置。
  // 重置后的表单元素恢复到菜单类型
  showFormItemByType(1);
};
// 暴露组件给父容器使用
defineExpose({
  openDialog,
});
</script>

<style lang="scss" scoped>

</style>
